<dom-module id="x-basic">
  <template>
    <div id="boundChild"
      value="{{ value }}"
      negvalue="{{!bool}}"
      attrvalue$="{{attrvalue}}"
      computedvalue="{{computedvalue}}"
      computedvaluetwo="{{computedvaluetwo}}"
      camel-case="{{value}}"
      computed-inline="{{computeInline(value,add, divide)}}"
      computed-inline2="{{computeInline(value, add,divide)}}"
      computedattribute$="{{computeInline(value, add,divide)}}"
      neg-computed-inline="{{!computeInline(value,add,divide)}}"
      style$="{{boundStyle}}"
      data-id$="{{dataSetId}}"
      custom-event-value="{{customEventValue::custom}}"
      custom-event-object-value="{{customEventObject.value::change}}"
      computed-from-mixed-literals='{{computeFromLiterals(3, "foo", bool)}}'
      computed-from-pure-literals='{{computeFromLiterals( 3, "foo")}}'
      computed-from-tricky-literals="{{computeFromTrickyLiterals(3, 'tricky\,\'zot\'')}}"
      computed-from-tricky-literals2='{{computeFromTrickyLiterals(3,"tricky\,&#39;zot&#39;" )}}'
      computed-from-no-args="{{computeFromNoArgs( )}}"
      no-computed="{{foobared(noInlineComputed)}}"
      >
      Test
      </div>
      <span id="boundText">{{text}}</span>
      <span idtest id="{{boundId}}"></span>
      <s id="computedContent">{{computeFromTrickyLiterals(3, 'tricky\,\'zot\'')}}</s>
      <input id="boundInput" value="{{text::input}}">
  </template>
  <script>
    Polymer({
      is: 'x-basic',
      properties: {
        value: {
          type: Number,
          observer: 'valueChanged',
          value: 10
        },
        computedvalue: {
          computed: 'computeValue(value)',
          observer: 'computedvalueChanged'
        },
        computedvaluetwo: {
          computed: 'computeValue(valuetwo)',
          observer: 'computedvaluetwoChanged'
        },
        notifyingvalue: {
          type: Number,
          notify: true,
          observer: 'notifyingvalueChanged'
        },
        computednotifyingvalue: {
          type: Number,
          notify: true,
          computed: 'computeNotifyingValue(notifyingvalue)'
        },
        computedFromMultipleValues: {
          type: Number,
          notify: true,
          computed: 'computeFromMultipleValues(sum1, sum2, divide)',
          observer: 'computedFromMultipleValuesChanged'
        },
        camelNotifyingValue: {
          type: Number,
          notify: true
        },
        readonlyvalue: {
          type: Number,
          readOnly: true,
          notify: true,
          observer: 'readonlyvalueChanged'
        },
        add: {
          value: 20
        },
        divide: {
          value: 2
        },
        customEventValue: {
          type: Number,
          observer: 'customEventValueChanged'
        },
        customEventObject: {
          type: Object,
          value: function() { return {}; }
        },
        boundId: {
          type: String,
          value: 'span'
        },
        noObserver: {
          observer: 'foobared'
        },
        noComputedProp: {
          computed: 'foobared(noComputed)'
        }
      },
      observers: [
        'multipleDepChangeHandler(dep1, dep2, dep3)',
        'customEventObjectValueChanged(customEventObject.value)',
        'foobared(noComplexObserver.*)'
      ],
      created: function() {
        this.observerCounts = {
          valueChanged: 0,
          computedvalueChanged: 0,
          computedvaluetwoChanged: 0,
          notifyingvalueChanged: 0,
          readonlyvalueChanged: 0,
          computedFromMultipleValuesChanged: 0,
          multipleDepChangeHandler: 0,
          customEventValueChanged: 0,
          customEventObjectValueChanged: 0
        };
      },
      clearObserverCounts: function() {
        for (var i in this.observerCounts) {
          this.observerCounts[i] = 0;
        }
      },
      valueChanged: function(val, old) {
        this.observerCounts.valueChanged++;
        assert.equal(arguments.length, 2, 'observer argument length wrong');
        assert.equal(val, this.value, 'observer value argument wrong');
        assert.equal(old, this._value, 'observer old argument wrong');
        this._value = val;
      },
      computeValue: function(val) {
        return val + 1;
      },
      computedvalueChanged: function(val, old) {
        this.observerCounts.computedvalueChanged++;
        assert.equal(arguments.length, 2, 'observer argument length wrong');
        assert.equal(val, this.computedvalue, 'observer value argument wrong');
        assert.equal(old, this._computedvalue, 'observer old argument wrong');
        this._computedvalue = val;
      },
      computedvaluetwoChanged: function(val, old) {
        this.observerCounts.computedvaluetwoChanged++;
        assert.equal(arguments.length, 2, 'observer argument length wrong');
        assert.equal(val, this.computedvaluetwo, 'observer value argument wrong');
        assert.equal(old, this._computedvaluetwo, 'observer old argument wrong');
        this._computedvaluetwo = val;
      },
      notifyingvalueChanged: function(val, old) {
        this.observerCounts.notifyingvalueChanged++;
        assert.equal(arguments.length, 2, 'observer argument length wrong');
        assert.equal(val, this.notifyingvalue, 'observer value argument wrong');
        assert.equal(old, this._notifyingvalue, 'observer old argument wrong');
        this._notifyingvalue = val;
      },
      readonlyvalueChanged: function(val, old) {
        this.observerCounts.readonlyvalueChanged++;
        assert.equal(arguments.length, 2, 'observer argument length wrong');
        assert.equal(val, this.readonlyvalue, 'observer value argument wrong');
        assert.equal(old, this._readonlyvalue, 'observer old argument wrong');
        this._readonlyvalue = val;
      },
      computeNotifyingValue: function(val) {
        return val + 2;
      },
      computeFromMultipleValues: function(sum1, sum2, divide) {
        assert.equal(arguments.length, 3, 'observer argument length wrong');
        assert.equal(sum1, this.sum1, 'observer value argument wrong');
        assert.equal(sum2, this.sum2, 'observer value argument wrong');
        assert.equal(divide, this.divide, 'observer value argument wrong');
        return (sum1 + sum2) / divide;
      },
      computedFromMultipleValuesChanged: function(val, old) {
        this.observerCounts.computedFromMultipleValuesChanged++;
        assert.equal(arguments.length, 2, 'observer argument length wrong');
        assert.equal(val, this.computedFromMultipleValues, 'observer value argument wrong');
        assert.equal(old, this._computedFromMultipleValues, 'observer old argument wrong');
        this._computedFromMultipleValues = val;
      },
      multipleDepChangeHandler: function(dep1, dep2, dep3) {
        this.observerCounts.multipleDepChangeHandler++;
        assert.equal(arguments.length, 3, 'observer argument length wrong');
        assert.equal(dep1, this.dep1, 'dependency 1 argument wrong');
        assert.equal(dep2, this.dep2, 'dependency 2 argument wrong');
        assert.equal(dep3, this.dep3, 'dependency 3 argument wrong');
      },
      computeInline: function(value, add, divide) {
        assert.equal(arguments.length, 3, 'observer argument length wrong');
        assert.equal(value, this.value, 'dependency 1 argument wrong');
        assert.equal(add, this.add, 'dependency 2 argument wrong');
        assert.equal(divide, this.divide, 'dependency 3 argument wrong');
        return (value + add) / divide;
      },
      customEventValueChanged: function(val, old) {
        this.observerCounts.customEventValueChanged++;
        assert.equal(arguments.length, 2, 'observer argument length wrong');
        assert.equal(val, this.customEventValue, 'observer value argument wrong');
        assert.equal(old, this._customEventValue, 'observer old argument wrong');
        this._customEventValue = val;
      },
      customEventObjectValueChanged: function(val) {
        this.observerCounts.customEventObjectValueChanged++;
        assert.equal(arguments.length, 1, 'observer argument length wrong');
        assert.equal(val, this.customEventObject.value, 'observer value argument wrong');
        // note, no `old` argument for path observers
      },
      computeFromLiterals: function(num, str) {
        assert.equal(num, 3);
        assert.equal(str, 'foo');
        return num + str;
      },
      computeFromTrickyLiterals: function(a, b) {
        return a + b;
      },
      computeFromNoArgs: function() {
        return 'no args!';
      }
    });
  </script>
</dom-module>

<dom-module id="x-compose">
  <template>
    <x-basic id="basic1"
      value="{{boundvalue}}"
      notifyingvalue="{{boundnotifyingvalue}}"
      camel-notifying-value="{{boundnotifyingvalue}}"
      computedvalue="{{boundcomputedvalue}}"
      computednotifyingvalue="{{boundcomputednotifyingvalue}}"
      readonlyvalue="{{boundreadonlyvalue}}">
    </x-basic>
    <x-basic id="basic2"
      value="[[boundvalue]]"
      notifyingvalue="[[boundnotifyingvalue]]"
      computedvalue="[[boundcomputedvalue]]"
      computednotifyingvalue="[[boundcomputednotifyingvalue]]">
    </x-basic>
  </template>
  <script>
    Polymer({
      is: 'x-compose',
      observers: [
        'boundvalueChanged(boundvalue)',
        'boundnotifyingvalueChanged(boundnotifyingvalue)',
        'boundcomputedvalueChanged(boundcomputedvalue)',
        'boundcomputednotifyingvalueChanged(boundcomputednotifyingvalue)',
        'boundreadonlyvalueChanged(boundreadonlyvalue)'
      ],
      created: function() {
        this.observerCounts = {
          boundvalueChanged: 0,
          boundnotifyingvalueChanged: 0,
          boundcomputedvalueChanged: 0,
          boundcomputednotifyingvalueChanged: 0,
          boundreadonlyvalueChanged: 0
        };
      },
      clearObserverCounts: function() {
        for (var i in this.observerCounts) {
          this.observerCounts[i] = 0;
        }
      },
      boundvalueChanged: function() {
        this.observerCounts.boundvalueChanged++;
      },
      boundnotifyingvalueChanged: function() {
        this.observerCounts.boundnotifyingvalueChanged++;
      },
      boundcomputedvalueChanged: function() {
        this.observerCounts.boundcomputedvalueChanged++;
      },
      boundcomputednotifyingvalueChanged: function() {
        this.observerCounts.boundcomputednotifyingvalueChanged++;
      },
      boundreadonlyvalueChanged: function() {
        this.observerCounts.boundreadonlyvalueChanged++;
      }
    });
  </script>
</dom-module>

<script>
  Polymer({
    is: 'x-reflect',
    properties: {
      reflectedobject: {
        type: Object,
        reflectToAttribute: true
      },
      reflectedarray: {
        type: Array,
        reflectToAttribute: true
      },
      reflectedNumber: {
        type: Number,
        reflectToAttribute: true
      },
      reflectedstring: {
        type: String,
        reflectToAttribute: true
      },
      reflectedboolean: {
        type: Boolean,
        reflectToAttribute: true
      },
      reflecteddate: {
        type: Date,
        reflectToAttribute: true
      }
    }
  });
</script>

<script>
  Polymer({
    is: 'x-notifies1',
    properties: {
      notifies: {
        notify: true
      }
    },
    ready: function() {
      this.notifies = 'readyValue';
    }
  });
</script>

<dom-module id="x-notifies2">
  <template>
    <x-notifies1 id="notifies1" notifies="{{shouldChange}}"></x-notifies1>
  </template>
</dom-module>
<script>
  Polymer({
    is: 'x-notifies2',
    properties: {
      notifies: {
        notify: true
      }
    }
  });
</script>

<dom-module id="x-notifies3">
  <template>
    <x-notifies2 id="notifies2" notifies="{{shouldNotChange}}"></x-notifies2>
  </template>
</dom-module>
<script>
  Polymer({
    is: 'x-notifies3',
    properties: {
      shouldNotChange: {
        observer: 'shouldNotChangeChanged'
      }
    },
    shouldNotChangeChanged: function() { }
  });
</script>
